<template>
  <div class="file-upload-wrapper">
    <!-- 隐藏的原生input元素 -->
    <input
      ref="fileInputRef"
      type="file"
      :accept="accept"
      :multiple="multiple"
      style="display: none"
      @change="handleFileChange"
    />
    
    <!-- 可点击的触发区域 -->
    <div
      class="upload-trigger"
      :class="{ 'upload-disabled': disabled, 'upload-loading': loading }"
      @click="triggerFileSelect"
      @keydown.enter="triggerFileSelect"
      @keydown.space.prevent="triggerFileSelect"
      tabindex="0"
      role="button"
      :aria-label="ariaLabel"
    >
      <slot>
        <div class="default-upload-content">
          <div class="upload-icon">📁</div>
          <div class="upload-text">点击选择文件</div>
        </div>
      </slot>
    </div>

    <!-- 拖拽区域（可选） -->
    <div
      v-if="enableDrop"
      class="drop-zone"
      :class="{ 'drop-active': isDragOver }"
      @drop="handleDrop"
      @dragover.prevent="handleDragOver"
      @dragenter.prevent="handleDragEnter"
      @dragleave="handleDragLeave"
    >
      <slot name="drop-zone">
        <div class="drop-zone-content">
          <div class="drop-icon">⬇️</div>
          <div class="drop-text">或拖拽文件到此处</div>
        </div>
      </slot>
    </div>

    <!-- 加载状态 -->
    <div v-if="loading" class="upload-loading-overlay">
      <div class="loading-spinner"></div>
      <div class="loading-text">{{ loadingText }}</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'

interface Props {
  accept?: string
  multiple?: boolean
  disabled?: boolean
  loading?: boolean
  loadingText?: string
  enableDrop?: boolean
  ariaLabel?: string
  maxSize?: number // 最大文件大小（字节）
  maxFiles?: number // 最大文件数量
}

interface Emits {
  (e: 'file-selected', files: File[]): void
  (e: 'file-error', error: string): void
}

const props = withDefaults(defineProps<Props>(), {
  accept: '*/*',
  multiple: false,
  disabled: false,
  loading: false,
  loadingText: '上传中...',
  enableDrop: false,
  ariaLabel: '选择文件',
  maxSize: 5 * 1024 * 1024, // 5MB
  maxFiles: 1
})

const emit = defineEmits<Emits>()

const fileInputRef = ref<HTMLInputElement>()
const isDragOver = ref(false)

// 触发文件选择
const triggerFileSelect = () => {
  if (props.disabled || props.loading) return
  
  try {
    fileInputRef.value?.click()
  } catch (error) {
    console.error('Failed to trigger file select:', error)
    emit('file-error', '无法打开文件选择器，请检查浏览器权限')
  }
}

// 验证文件
const validateFiles = (files: File[]): { valid: File[], errors: string[] } => {
  const valid: File[] = []
  const errors: string[] = []

  // 检查文件数量
  if (files.length > props.maxFiles) {
    errors.push(`最多只能选择 ${props.maxFiles} 个文件`)
    return { valid, errors }
  }

  for (const file of files) {
    // 检查文件大小
    if (file.size > props.maxSize) {
      errors.push(`文件 "${file.name}" 大小超过限制 (${(props.maxSize / 1024 / 1024).toFixed(1)}MB)`)
      continue
    }

    // 检查文件类型
    if (props.accept !== '*/*') {
      const acceptTypes = props.accept.split(',').map(type => type.trim())
      const isValidType = acceptTypes.some(acceptType => {
        if (acceptType.startsWith('.')) {
          // 扩展名匹配
          return file.name.toLowerCase().endsWith(acceptType.toLowerCase())
        } else if (acceptType.includes('/*')) {
          // MIME类型通配符匹配
          const baseType = acceptType.split('/')[0]
          return file.type.startsWith(baseType + '/')
        } else {
          // 精确MIME类型匹配
          return file.type === acceptType
        }
      })

      if (!isValidType) {
        errors.push(`文件 "${file.name}" 类型不支持`)
        continue
      }
    }

    valid.push(file)
  }

  return { valid, errors }
}

// 处理文件选择
const handleFileChange = (event: Event) => {
  const target = event.target as HTMLInputElement
  const files = Array.from(target.files || [])
  
  if (files.length === 0) return

  const { valid, errors } = validateFiles(files)

  if (errors.length > 0) {
    emit('file-error', errors.join('; '))
  }

  if (valid.length > 0) {
    emit('file-selected', valid)
  }

  // 清空input值，允许重复选择同一文件
  target.value = ''
}

// 拖拽处理
const handleDragEnter = (event: DragEvent) => {
  event.preventDefault()
  isDragOver.value = true
}

const handleDragOver = (event: DragEvent) => {
  event.preventDefault()
}

const handleDragLeave = (event: DragEvent) => {
  event.preventDefault()
  // 只有当离开整个拖拽区域时才设置为false
  if (!event.currentTarget?.contains(event.relatedTarget as Node)) {
    isDragOver.value = false
  }
}

const handleDrop = (event: DragEvent) => {
  event.preventDefault()
  isDragOver.value = false

  if (props.disabled || props.loading) return

  const files = Array.from(event.dataTransfer?.files || [])
  if (files.length === 0) return

  const { valid, errors } = validateFiles(files)

  if (errors.length > 0) {
    emit('file-error', errors.join('; '))
  }

  if (valid.length > 0) {
    emit('file-selected', valid)
  }
}

// 暴露方法给父组件
defineExpose({
  triggerFileSelect,
  reset: () => {
    if (fileInputRef.value) {
      fileInputRef.value.value = ''
    }
  }
})
</script>

<style scoped>
.file-upload-wrapper {
  position: relative;
}

.upload-trigger {
  cursor: pointer;
  transition: all 0.3s ease;
  outline: none;
}

.upload-trigger:hover:not(.upload-disabled):not(.upload-loading) {
  opacity: 0.8;
}

.upload-trigger:focus {
  box-shadow: 0 0 0 2px #1890ff;
}

.upload-disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

.upload-loading {
  cursor: wait;
  opacity: 0.7;
}

.default-upload-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px;
  border: 2px dashed #d9d9d9;
  border-radius: 6px;
  background: #fafafa;
}

.upload-icon {
  font-size: 24px;
  margin-bottom: 8px;
}

.upload-text {
  color: #666;
  font-size: 14px;
}

.drop-zone {
  margin-top: 10px;
  padding: 15px;
  border: 2px dashed #d9d9d9;
  border-radius: 6px;
  background: #f9f9f9;
  text-align: center;
  transition: all 0.3s ease;
}

.drop-zone.drop-active {
  border-color: #1890ff;
  background: #e6f7ff;
}

.drop-zone-content {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.drop-icon {
  font-size: 20px;
  margin-bottom: 5px;
}

.drop-text {
  color: #666;
  font-size: 12px;
}

.upload-loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(255, 255, 255, 0.8);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
}

.loading-spinner {
  width: 20px;
  height: 20px;
  border: 2px solid #f3f3f3;
  border-top: 2px solid #1890ff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-bottom: 8px;
}

.loading-text {
  color: #666;
  font-size: 12px;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
</style>
